﻿Imports StackExchange.Redis
Imports System.IO
Imports System.Threading.Thread


Public Class RedisChat
    Dim ru As RedisUtil = New RedisUtil
    Dim db As IDatabase
    Dim isub As ISubscriber
    Dim errorUser As String = "管理员,全部,系统"
    Public Delegate Sub dgAddNote(ByRef txt As String)
    Public Delegate Sub dgRefreshUserlist()
    Dim thdRefresh As New System.Threading.Thread(AddressOf myThread)
    Dim thdCleanuser As New System.Threading.Thread(AddressOf cleanUser)
    Dim bExitThread As Boolean = False
    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        If MessageBox.Show("确定要退出程序吗？", "退出", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
            e.Cancel = False
            Environment.Exit(0)
        Else
            e.Cancel = True
        End If
    End Sub


    Private Sub RedisChat_ClientSizeChanged(sender As Object, e As EventArgs) Handles MyBase.ClientSizeChanged
        lvusers.Height = Me.Height - 100
        txtsend.Top = lvusers.Top + lvusers.Height - 100
        txtsend.Width = Me.Width - 240

        btnclear.Top = txtsend.Top + 60
        btnsend.Top = txtsend.Top
        btnsend.Left = Me.Width - 110
        btnclear.Left = btnsend.Left
        txtnote.Width = Me.Width - 170
        txtnote.Height = Me.Height - 215
    End Sub

    Private Sub btnsend_Click(sender As Object, e As EventArgs) Handles btnsend.Click
        If lvusers.SelectedIndex > -1 Then
            Dim sel As String = lvusers.SelectedItem.ToString
            If sel.CompareTo(edtuser.Text) = 0 Then
                MessageBox.Show("不能给自己发消息哦！", "错误")
                Return
            End If
            If lvusers.SelectedIndex = 0 Then
                ru.publish(New MsgObj With {.sRec = "all", .sMsg = txtsend.Text.Trim, .sSender = edtuser.Text, .sSendTime = DateTime.Now.ToString})
            Else
                ru.publish(New MsgObj With {.sRec = sel, .sMsg = txtsend.Text.Trim, .sSender = edtuser.Text, .sSendTime = DateTime.Now.ToString})
            End If
            addNote("我发给 " & lvusers.SelectedItem.ToString & ":" & txtsend.Text.Trim)
            txtsend.Text = ""
        Else
            MessageBox.Show("你要发信息给谁？", "提示")
        End If

    End Sub
    Private Sub cleanUser()

        Dim lastcheck = DateTime.Now.AddMinutes(-3) '只保留三分钟内有心跳的用户
        'MsgBox("will delete:" & CDbl(lastcheck.Ticks / 1000))
        '开始检测并删除10分钟没有响应的
        db.SortedSetRemoveRangeByScore("userlist", 0.1, CDbl(lastcheck.Ticks / 1000))
        System.Threading.Thread.Sleep(60000)
    End Sub
    Private Sub myThread()
        While Not bExitThread
            System.Threading.Thread.Sleep(60000) '60sec
            '更新自己的在线状态
            updateSelfOnline()
            Me.Invoke(New dgRefreshUserlist(AddressOf refreshUserlist))

            '清理过期用户
            'If db.LockTake("cleanuser", 1, TimeSpan.FromSeconds(1200)) Then
            thdCleanuser.Start()

            'Else

            'End If

        End While
    End Sub
    Private Sub updateSelfOnline()
        db.SortedSetAdd("userlist", edtuser.Text, CDbl(DateTime.Now.Ticks / 1000))
    End Sub
    Private Sub btnclear_Click(sender As Object, e As EventArgs) Handles btnclear.Click
        If MessageBox.Show("确定要清空聊天记录吗？", "清空", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
            txtnote.Text = ""
        End If
    End Sub
    Private Sub addNote(ByRef txt As String)
        txtnote.AppendText(DateTime.Now.ToString & " " & txt & vbCrLf)
    End Sub
    Private Sub gotMsg(msg As MsgObj)
        '检测是否是新上线的用户
        If Not lvusers.Items.Contains(msg.sSender) Then
            '新用户
            lvusers.Items.Add(msg.sSender)
        End If
        If msg.sRec.CompareTo(edtuser.Text.Trim) = 0 Then
            Me.Invoke(New dgAddNote(AddressOf addNote), msg.sSender & " 发来私信:" & msg.sMsg)
        Else
            Me.Invoke(New dgAddNote(AddressOf addNote), msg.sSender & " 发来广播:" & msg.sMsg)
        End If

    End Sub

    Private Sub refreshUserlist()
        addNote("开始刷新用户")
        Dim lst = db.SortedSetRangeByScore("userlist")
        lvusers.Items.Clear()
        lvusers.Items.Add("全部用户")
        For Each it As RedisValue In lst
            lvusers.Items.Add(it.ToString)
        Next
        addNote("用户刷新完毕")
    End Sub
    Private Sub btnconnect_Click(sender As Object, e As EventArgs) Handles btnconnect.Click

        If btnconnect.Text.CompareTo("连接") = 0 Then
            For Each eu As String In errorUser.Split(",")
                If edtuser.Text.Trim.Contains(eu) Then
                    MessageBox.Show("您的用户名包含非法词汇:" & eu & "请予以修改！", "错误")
                    Return
                End If
            Next
            If Not thdRefresh.IsAlive Then
                thdRefresh = New System.Threading.Thread(AddressOf myThread)
                thdRefresh.Start()
                addNote("心跳线程启动")
            End If

            edtuser.Text = edtuser.Text.Trim
            Try
                ru.init(edtserver.Text.Trim & ",password=" & edtpwd.Text.Trim)
                db = ConnectionMultiplexer.Connect(edtserver.Text.Trim & ",password=" & edtpwd.Text.Trim).GetDatabase(0)
                isub = ConnectionMultiplexer.Connect(edtserver.Text.Trim & ",password=" & edtpwd.Text.Trim).GetSubscriber
                Dim chns(1) As String
                chns(0) = edtuser.Text.Trim
                chns(1) = "all"
                For Each chn As String In chns

                    isub.Subscribe(New RedisChannel(chn, RedisChannel.PatternMode.Auto), Function(chnarg As RedisChannel, vvv As RedisValue)
                                                                                             Dim msg As MsgObj = ru.decMsg(vvv)
                                                                                             gotMsg(msg)
                                                                                             'Console.WriteLine(msg.sMsg)
                                                                                         End Function
                       )

                Next
                edtuser.Enabled = False
                edtserver.Enabled = False
                edtpwd.Enabled = False
                btnconnect.Text = "断开"
                lvusers.Items.Add(edtuser.Text.Trim)
                updateSelfOnline()
                refreshUserlist()
                Me.Text = "RedisChat [" & edtuser.Text & "]"
            Catch ex As Exception
                MessageBox.Show("发生错误:" & ex.Message)
            End Try
            If File.Exists("setting.conf") Then
                Using tw = New IO.StreamWriter("setting.conf")
                    tw.WriteLine(edtserver.Text)
                    tw.WriteLine(edtpwd.Text)
                    tw.WriteLine(edtuser.Text)
                    tw.Flush()
                End Using
            ElseIf (DialogResult.Yes = MessageBox.Show("要保存配置文件不？", "询问", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) Then
                Using tw = New IO.StreamWriter("setting.conf")
                    tw.WriteLine(edtserver.Text)
                    tw.WriteLine(edtpwd.Text)
                    tw.WriteLine(edtuser.Text)
                    tw.Flush()
                End Using
            End If
        Else
            Me.Text = "RedisChat"
            edtuser.Enabled = True
            edtserver.Enabled = True
            edtpwd.Enabled = True
            btnconnect.Text = "连接"
            isub.UnsubscribeAll()
            db.Multiplexer.Close()
            lvusers.Items.Clear()
            Try
                thdRefresh.Abort()
            Catch ex As Exception

            End Try
        End If
    End Sub

    Private Sub RedisChat_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        If File.Exists("setting.conf") Then
            Using tr As New StreamReader("setting.conf")
                edtserver.Text = tr.ReadLine
                edtpwd.Text = tr.ReadLine
                edtuser.Text = tr.ReadLine
            End Using
        End If

    End Sub

    Private Sub btnrefreshuserlist_Click(sender As Object, e As EventArgs) Handles btnrefreshuserlist.Click
        If btnconnect.Text.CompareTo("连接") = 0 Then
            MessageBox.Show("尚未连接", "错误")
            Return
        End If
        refreshUserlist()
    End Sub

    Private Sub lvusers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lvusers.SelectedIndexChanged
        Me.Text = "与[" & lvusers.SelectedItem.ToString & "] 交谈中 - RedisChat"
    End Sub
End Class
